home *** CD-ROM | disk | FTP | other *** search
/ Aminet 16 / Aminet 16 (1996)(GTI - Schatztruhe)[!][Dec 1996].iso / Aminet / comm / bbs / Cit_Src_6J12.lha / msgadd.c < prev    next >
C/C++ Source or Header  |  1996-10-13  |  33KB  |  1,508 lines

  1. /*
  2.  *                              msgadd.c
  3.  *
  4.  * External Message handler.  For use with external OtherNet parsers.
  5.  */
  6. #define VIEWING (1)
  7. /*
  8.  *                              history
  9.  *
  10.  * 96Sep01 AFP  V1.5 -- support vortex checking and archiving by month & year
  11.  * 91Mar31 HAW  v1.4 -- support for virtual rooms.
  12.  * 90Aug13 HAW  v1.3 -- support for room archiving.
  13.  * 89Oct23 HAW  v1.2 -- support for incoming route mail.
  14.  * 88Nov05 HAW  Created.
  15.  */
  16. #include <stdio.h>
  17. #include <string.h>
  18. #include <math.h>
  19. #include <time.h>
  20. #include "ctdl.h"
  21. /*
  22.  *                              contents
  23.  *
  24.  */
  25.  
  26. #define TITLE           "C86Net Message Importer"
  27.  
  28. extern int debug_flag;
  29.  
  30.  
  31. #define NO_ERROR        0
  32. #define BAD_ARGS        1
  33. #define BAD_TABLE       2
  34. #define NO_NODE         3
  35. #define FATAL           4
  36. #define LF_ERROR        5
  37.  
  38. int       crtColumn;
  39. extern CONFIG cfg;                /* Configuration variables      */
  40. extern MessageBuffer msgBuf;      /* The -sole- message buffer    */
  41. extern aRoom roomBuf;             /* Room buffer  */
  42. extern logBuffer logBuf;
  43. extern FILE *roomfl,
  44.          *logfl;
  45. extern int thisRoom;              /* Current room */
  46. extern rTable *roomTab;
  47. extern struct mBuf mFile1,
  48.           mFile2;
  49. extern NetTable *netTab;
  50. extern NetBuffer netBuf;
  51. extern NetBuffer netTemp;
  52. extern FILE *netfl;
  53. extern LogTable *logTab;
  54. extern int thisNet;               /* Current node in use  */
  55. extern char *APPEND_ANY;
  56. extern char *APPEND_TEXT;
  57. extern FILE *msgfl,
  58.          *msgfl2;
  59. FILE     *GlobalFd;
  60. int       RouteSlot;
  61. extern FILE *upfd;
  62. char      inNet = NORMAL_NET;
  63.  
  64. FILE     *netLog = stderr;
  65. char      logNetResults = TRUE;
  66. char      netDebug = TRUE;
  67.  
  68. SListBase MailForward =
  69. {NULL, NULL, NULL, NULL, NULL};
  70. SListBase Arch_base =
  71. {NULL, ChkNtoStr, NULL, FreeNtoStr, EatNMapStr};
  72. static char EOP = FALSE;
  73. char     *R_SH_MARK = "&&";
  74. char     *NON_LOC_NET = "%%";
  75. char     *LOC_NET = "++";
  76.  
  77. #ifdef ANSI_PROTOTYPING
  78.  
  79. void      GenInit (void);
  80. void      Process (char *fn);
  81. int       GetOtherNetChar (void);
  82. int       VirtualShared (int NetNo, label name);
  83. int       VirtualExists (label name);
  84. void      SaveIt (void);
  85. int       FindPerson (label nm, logBuffer * lbuf);
  86. int       FindRoom (label nm);
  87. int       FindNet (label nm, NetBuffer * netBuf);
  88. void      AddVirtualField (char field, char *contents);
  89. void      PutMessage (void);
  90. void      HandleRouted (void);
  91. void      AddField (int field, char *fValue);
  92. int       FindPos (void);
  93. void      VirtualHandle (void);
  94. int       MARecVirtualRoom (int VirtIndex);
  95. void      TranslateFilename (char *realfn, char *fn);
  96. void      netResult (char *);
  97.  
  98. #endif
  99.  
  100. int
  101. mPrintf (char *format,...)
  102. {
  103.   return 0;
  104. }       /* stub to quiet the linker */
  105.  
  106. /*
  107.  * crashout()
  108.  *
  109.  * Big error handler.
  110.  */
  111. void
  112. crashout (str)
  113.   char     *str;
  114. {
  115.   printf (str);
  116.   exit (FATAL);
  117. }
  118.  
  119. /*
  120.  * main()
  121.  *
  122.  * This is the main manager.
  123.  */
  124. int       main (int, char **);
  125. int
  126. main (argc, argv)
  127.   char    **argv;
  128.   int       argc;
  129. {
  130.   int       rover;
  131.  
  132.   printf ("%s %s\n%s\n\n", TITLE, VERSION_NAME, COPYRIGHT);
  133. /*
  134.  if name starts with a D, this is a debug session
  135. */
  136.   debug_flag = ( argv[0][0] == 'D' ) ? 1 : 0;
  137. /*
  138.  not enough arguments?  Explain.
  139. */
  140.   if (argc < 3)
  141.     {
  142.       printf ("usage: MSGADD nodename file [ file ... ]\n");
  143.       printf ("\nEach file may contain one or more messages in C86Net format.\n");
  144.       exit (BAD_ARGS);
  145.     }
  146.  
  147.   cfg.weAre = UTILITY;
  148.   if (!readSysTab (TRUE, TRUE))
  149.     {
  150.       exit (BAD_TABLE);
  151.     }
  152.  
  153.   if (access (LOCKFILE, 0) != -1)
  154.     {
  155.       printf ("Please do not run MsgAdd using Outside Commands.\n");
  156.       writeSysTab ();
  157.       exit (LF_ERROR);
  158.     }
  159.  
  160.   GenInit ();
  161.   VirtInit ();
  162.   VortexInit ();
  163.   InitVortexing ();
  164.  
  165.   if (FindNet (argv[1], &netBuf) == ERROR)
  166.     {
  167.       writeSysTab ();
  168.       printf ("Could not find node %s.\n", argv[1]);
  169.       exit (NO_NODE);
  170.     }
  171.  
  172.   for (rover = 2; rover < argc; rover++)
  173.     Process (argv[rover]);
  174.  
  175.   FinVortexing ();      /* cleanup and report errors */
  176.   UpdVirtStuff ();
  177.   writeSysTab ();
  178.  
  179.   return 0;
  180. }
  181.  
  182. /*
  183.  * GenInit()
  184.  *
  185.  * This is a general initialization routine.
  186.  */
  187. void
  188. GenInit ()
  189. {
  190.   SYS_FILE  fn;
  191.  
  192.   initNetBuf (&netBuf);
  193.   initNetBuf (&netTemp);
  194.   makeSysName (fn, "ctdlnet.sys", &cfg.netArea);
  195.   openFile (fn, &netfl);
  196.  
  197.   initRoomBuf (&roomBuf);
  198.   makeSysName (fn, "ctdlroom.sys", &cfg.roomArea);
  199.   openFile (fn, &roomfl);
  200.  
  201.   InitMsgBase ();
  202.  
  203.   initLogBuf (&logBuf);
  204.   makeSysName (fn, "ctdllog.sys", &cfg.logArea);
  205.   openFile (fn, &logfl);
  206.  
  207.   makeSysName (fn, "ctdlarch.sys", &cfg.roomArea);
  208.   MakeList (&Arch_base, fn, NULL);
  209. }
  210.  
  211. /*
  212.  * Process()
  213.  *
  214.  * This will process a file - read a file for all messages and stuff them
  215.  * into the message base.
  216.  */
  217. void
  218. Process (fn)
  219.   char     *fn;
  220. {
  221.   extern char *READ_ANY;
  222.  
  223.   if ((GlobalFd = fopen (fn, READ_ANY)) == NULL)
  224.     {
  225.       printf ("ERROR: Could not open %s.\n", fn);
  226.       return;
  227.     }
  228.  
  229.   while (getMessage (GetOtherNetChar, TRUE, TRUE, TRUE))
  230.     SaveIt ();
  231.  
  232.   fclose (GlobalFd);
  233. }
  234.  
  235. /*
  236.  * GetOtherNetChar()
  237.  *
  238.  * This gets a character for getMessage.
  239.  */
  240. int
  241. GetOtherNetChar ()
  242. {
  243.   int       c;
  244.  
  245.   c = getc (GlobalFd);
  246.   if (c == EOF)
  247.     return -1;
  248.   return c;
  249. }
  250.  
  251. /*
  252.  * SaveIt()
  253.  *
  254.  * This is charged with saving the message in the database.
  255.  *
  256.  * 1. If mail, must do recipient validation.
  257.  * 2. Must validate room.
  258.  */
  259. void
  260. SaveIt ()
  261. {
  262.   int       LogSlot,
  263.             RoomSlot,
  264.             place;
  265.   extern char *NON_LOC_NET,
  266.            *LOC_NET;
  267.   char     *fn,
  268.            *realfn;
  269.  
  270. #ifdef VIEWING
  271.   printf ("mbauth=-%s-\n", msgBuf.mbauth);
  272.   printf ("mbroom=-%s-\n", msgBuf.mbroom);
  273.   printf ("mbdate=-%s-\n", msgBuf.mbdate);
  274.   printf ("mbtime=-%s-\n", msgBuf.mbtime);
  275.   printf ("mboname=-%s-\n", msgBuf.mboname);
  276.   printf ("mborig=-%s-\n", msgBuf.mborig);
  277.   printf ("mbto=-%s-\n", msgBuf.mbto);
  278.   printf ("mbsrcId=-%s-\n", msgBuf.mbsrcId);
  279.   printf ("mbtext=-%s-\n", msgBuf.mbtext);
  280.   printf ("\n");
  281. #endif
  282.  
  283.   if (VirtualExists (msgBuf.mbroom) != ERROR)
  284.     {
  285.       VirtualHandle ();
  286.       return;
  287.     };
  288.  
  289.   if (strLen (msgBuf.mbaddr) != 0)
  290.     {
  291.       HandleRouted ();
  292.     }
  293.   else if (strCmpU (msgBuf.mbroom, "mail") == SAMESTRING)
  294.     {
  295.       if ((LogSlot = FindPerson (msgBuf.mbto, &logBuf)) == ERROR)
  296.         {
  297.           printf ("Could not deliver Mail to '%s', does not exist.\n",
  298.                   msgBuf.mbto);
  299.           return;
  300.         }
  301.       noteAMessage (logBuf.lbMail, MAILSLOTS, cfg.newest + 1, cfg.catSector);
  302.       putLog (&logBuf, LogSlot);
  303.     }
  304.   else
  305.     {
  306.       if ((RoomSlot = FindRoom (msgBuf.mbroom)) == ERROR)
  307.         {
  308.           printf ("Message meant for non-existent room '%s' not incorporated.\n",
  309.                   msgBuf.mbroom);
  310.           return;
  311.         };
  312.       if (!NotVortex ())
  313.         {
  314.           printf ("Message is a duplicate, not incorporated.\n");
  315.           printf ("Author:%20s   ", msgBuf.mbauth);
  316.           printf ("Room:%s\n", msgBuf.mbroom);
  317.           printf ("  date:%20s   ", msgBuf.mbdate);
  318.           printf ("time:%s\n", msgBuf.mbtime);
  319.           printf (" Oname:%20s   ", msgBuf.mboname);
  320.           printf ("orig:%s\n", msgBuf.mborig);
  321.           printf ("    to:%20s   ", msgBuf.mbto);
  322.           printf (" src:%s\n", msgBuf.mbsrcId);
  323.           return;
  324.         };
  325.       noteAMessage (roomBuf.msg, MSGSPERRM, cfg.newest + 1, cfg.catSector);
  326.       roomTab[RoomSlot].rtlastMessage = cfg.newest + 1;
  327.       putRoom (RoomSlot);
  328.       if ((place = FindPos ()) == ERROR)
  329.         printf ("WARNING: msg for %s is not formally shared.\n",
  330.                 msgBuf.mbroom);
  331.  
  332.       if (roomBuf.rbShareType != PEON &&
  333.           netBuf.netRooms[place].mode != PEON)
  334.         strCpy (msgBuf.mbaddr, NON_LOC_NET);
  335.       else
  336.         strCpy (msgBuf.mbaddr, LOC_NET);
  337.  
  338.       if (roomBuf.rbflags.ARCHIVE == 1)
  339.         {
  340.           fn = SearchList (&Arch_base, NtoStrInit (thisRoom, "", 0, TRUE));
  341.           realfn = GetDynamic (strlen (fn) + 15);
  342.           TranslateFilename (realfn, fn);
  343.           if( debug_flag ) printf(" Filename;%s is now %s\n",fn,realfn);
  344.           if ((upfd = fopen (realfn, APPEND_TEXT)) != NULL)
  345.             {
  346.               if (msgBuf.mbdate[0])fprintf (upfd, "   %s ", msgBuf.mbdate);
  347.               if (msgBuf.mbtime[0] && sendTime)fprintf (upfd, "%s ", msgBuf.mbtime);
  348.               if (msgBuf.mbauth[0]) fprintf (upfd, "from %s", msgBuf.mbauth);
  349.               NormStr (msgBuf.mboname);
  350.               if (msgBuf.mboname[0])
  351.                 {
  352.                   fprintf (upfd, " @ %s", msgBuf.mboname);
  353.                   if (msgBuf.mbdomain[0])fprintf (upfd, cfg.DomainDisplay, msgBuf.mbdomain);
  354.                 };
  355.  
  356.               if (msgBuf.mbto[0]) fprintf (upfd, " to %s", msgBuf.mbto);
  357.               crtColumn = 1;
  358.               mFormat (msgBuf.mbtext);
  359.               fprintf (upfd, "\n");
  360.               fclose (upfd);
  361.             };
  362.           free(realfn);
  363.         }
  364.     }
  365.   strCpy (msgBuf.mborig, netBuf.netId);
  366.   PutMessage ();
  367.   cfg.newest++;
  368.  
  369.   cfg.catSector = mFile1.thisSector;
  370.   cfg.catChar = mFile1.thisChar;
  371. }
  372.  
  373. SListBase FwdAliasii;             /* keeps some other stuff happy */
  374. char      onConsole = FALSE,
  375.           remoteSysop = FALSE;
  376. int       callSlot = ERROR;
  377.  
  378. /*
  379.  * HandleRouted()
  380.  *
  381.  * This should handle mail routing incoming.
  382.  */
  383. void
  384. HandleRouted ()
  385. {
  386.   char     *AltName;
  387.   label     Name,
  388.             Id,
  389.             temp;
  390.   SYS_FILE  fn;
  391.   extern void (*NetPrintTarget) (char *fmt,...);
  392.   extern int (*ToFileWork) ();
  393.  
  394. /* no find? */
  395.   if ((RouteSlot = FindNet (msgBuf.mbaddr, &netTemp)) == ERROR)
  396.     {
  397.       return;
  398.     }
  399.  
  400. /* yes, found, data in netTemp - will we do the routing? */
  401.   if (!cfg.BoolFlags.RouteMail || !netTemp.nbflags.RouteTo)
  402.     {
  403.       return;
  404.     }
  405.  
  406. /* yes, we'll do the routing.  Now to figure it out. */
  407.   strCpy (Name, netTemp.netName);
  408.   strCpy (Id, netTemp.netId);
  409.  
  410.   if ((AltName = UseNetAlias (Name, TRUE)) != NULL)
  411.     strCpy (Name, AltName);
  412.  
  413.   if (FindRouteSlot () == ERROR)
  414.     {
  415.       return;
  416.     }
  417.  
  418. /* Ugly ugly kludge until we figure out how nbHiRouteInd is wrong */
  419.   if (netTemp.nbHiRouteInd < 0)
  420.     netTemp.nbHiRouteInd = 0;
  421.   sPrintf (temp, "R%d.%d", RouteSlot, netTemp.nbHiRouteInd++);
  422.  
  423.   makeSysName (fn, temp, &cfg.netArea);
  424.  
  425.   if ((upfd = safeopen (fn, APPEND_ANY)) == NULL)
  426.     {
  427.       return;
  428.     }
  429.  
  430.   fprintf (upfd, "%-20s", Id);
  431.   putc (0, upfd);
  432.   fprintf (upfd, "%-20s", Name);
  433.   putc (0, upfd);
  434.  
  435.   NetPrintTarget = ToFile;
  436.   StartEncode (putFLChar);
  437.   ToFileWork = Encode;
  438.   prNetStyle (TRUE, Encode, FALSE, "");
  439.   StopEncode ();
  440.   fclose (upfd);
  441.   netTemp.nbflags.HasRouted = TRUE;
  442.  
  443.   putNet (RouteSlot, &netTemp);
  444. }
  445.  
  446. /*
  447.  * FindPerson()
  448.  *
  449.  * This loads the log record for the named person.
  450.  * RETURNS: ERROR if not found, else log record #
  451.  * (stolen from LOG.C)
  452.  */
  453. int
  454. FindPerson (name, lBuf)
  455.   char     *name;
  456.   logBuffer *lBuf;
  457. {
  458.   int       h,
  459.             i,
  460.             foundIt,
  461.             logNo;
  462.  
  463.   if (strCmpU (name, "Citadel") != SAMESTRING)
  464.     {
  465.       h = hash (name);
  466.       for (foundIt = i = 0; i < cfg.MAXLOGTAB && !foundIt; i++)
  467.         {
  468.           if (logTab[i].ltnmhash == h)
  469.             {
  470.               getLog (lBuf, logNo = logTab[i].ltlogSlot);
  471.               if (lBuf->lbflags.L_INUSE &&
  472.                   strCmpU (name, lBuf->lbname) == SAMESTRING)
  473.                 {
  474.                   foundIt = TRUE;
  475.                 }
  476.             }
  477.         }
  478.     }
  479.   else
  480.     foundIt = FALSE;
  481.   if (!foundIt)
  482.     return ERROR;
  483.   else
  484.     return logNo;
  485. }
  486.  
  487. /*
  488.  * findRoom()
  489.  *
  490.  * This function should find the named room.  Return ERROR if not found.
  491.  */
  492. int
  493. FindRoom (nm)
  494.   label     nm;
  495. {
  496.   int       rover;
  497.  
  498.   for (rover = 0; rover < MAXROOMS; rover++)
  499.     if (strCmpU (roomTab[rover].rtname, nm) == SAMESTRING)
  500.       {
  501.         getRoom (rover);
  502.         return rover;
  503.       }
  504.  
  505.   return ERROR;
  506. }
  507.  
  508. /*
  509.  * noteAMessage()
  510.  *
  511.  * This function notes a message in a message array.  Stolen from MSG.C.
  512.  */
  513. void
  514. noteAMessage (base, slots, id, loc)
  515.   MSG_NUMBER id;
  516.   SECTOR_ID loc;
  517.   theMessages *base;
  518.   int       slots;
  519. {
  520.   int       i;
  521.  
  522. /* store into current room: */
  523. /* slide message pointers down to make room for this one:       */
  524.   for (i = 0; i < slots - 1; i++)
  525.     {
  526.       base[i].rbmsgLoc = base[i + 1].rbmsgLoc;
  527.       base[i].rbmsgNo = base[i + 1].rbmsgNo;
  528.     }
  529.  
  530. /* slot this message in:    */
  531.   base[slots - 1].rbmsgNo = id;
  532.   base[slots - 1].rbmsgLoc = loc;
  533. }
  534.  
  535. /*
  536.  * FindNet()
  537.  *
  538.  * This function will find the named node.  Stolen from searchNameNet/NETMISC.
  539.  */
  540. int
  541. FindNet (label nm, NetBuffer * nBuf)
  542. {
  543.   int       rover;
  544.  
  545.   for (rover = 0; rover < cfg.netSize; rover++)
  546.     {
  547.       if (netTab[rover].ntflags.in_use &&
  548.           hash (nm) == netTab[rover].ntnmhash)
  549.         {
  550.           getNet (rover, nBuf);
  551.           if (strCmpU (nBuf->netName, nm) == SAMESTRING)
  552.             return rover;
  553.         }
  554.     }
  555.   return ERROR;
  556. }
  557.  
  558. /*
  559.  * FindPos()
  560.  *
  561.  * This finds the spot in the shared room array for the node that matches up
  562.  * with the current room.
  563.  */
  564. int
  565. FindPos ()
  566. {
  567.   int       rover;
  568.  
  569.   for (rover = 0; rover < SHARED_ROOMS; rover++)
  570.     if (isSharedRoom (thisNet, rover) &&
  571.         netRoomSlot (rover) == thisRoom &&
  572.         netGen (thisNet, rover) == roomBuf.rbgen)
  573.       return rover;
  574.  
  575.   return ERROR;
  576. }
  577.  
  578. /*
  579.  * VirtualHandle()
  580.  *
  581.  * This function will handle a message destined for a virt room.
  582.  */
  583. void
  584. VirtualHandle ()
  585. {
  586.   int       Vindex;
  587.  
  588.   if ((Vindex = VirtualShared (thisNet, msgBuf.mbroom)) == ERROR)
  589.     {
  590.       printf ("Virtual room %s not shared with %s, message not saved.\n",
  591.               msgBuf.mbroom, netBuf.netName);
  592.       return;
  593.     }
  594.   MARecVirtualRoom (Vindex);
  595. }
  596.  
  597. /*********** These functions stolen & modified from VIRT2.C ***************/
  598.  
  599. extern VirtualRoom *VRoomTab;
  600. extern VirtNet *VirtNetList;
  601. extern int VirtSize,
  602.           VNetSize;
  603.  
  604. /*
  605.  * MARecVirtualRoom()
  606.  *
  607.  * This function receives a virtual room from another system.
  608.  */
  609. int
  610. MARecVirtualRoom (int VirtIndex)
  611. {
  612.   int       VirtNo;
  613.   MSG_NUMBER rover;
  614.   char     *distance,
  615.             fn[50];
  616.   extern FILE *upfd;
  617.   extern char *WRITE_ANY;
  618.  
  619.   VirtNo = VirtNetList[thisNet].VirtList[VirtIndex].WhichVirt;
  620.  
  621.   if (VirtNetList[thisNet].VirtList[VirtIndex].mode != PEON)
  622.     {
  623.       distance = LD_DIR;
  624.       rover = VRoomTab[VirtNo].vrHiLD + 1l;
  625.       VRoomTab[VirtNo].vrChanged |= LD_CHANGE;
  626.     }
  627.   else
  628.     {
  629.       distance = LOCAL_DIR;
  630.       rover = VRoomTab[VirtNo].vrHiLocal + 1l;
  631.       VRoomTab[VirtNo].vrChanged |= LOC_CHANGE;
  632.     }
  633.   CreateVAName (fn, VirtNo, distance, rover);
  634.  
  635.   if ((upfd = fopen (fn, WRITE_ANY)) != NULL)
  636.     {
  637.       if (msgBuf.mbauth[0])
  638.         AddVirtualField ('A', msgBuf.mbauth);
  639.       if (msgBuf.mbdate[0])
  640.         AddVirtualField ('D', msgBuf.mbdate);
  641.       if (msgBuf.mbtime[0])
  642.         AddVirtualField ('C', msgBuf.mbtime);
  643.       if (msgBuf.mboname[0])
  644.         AddVirtualField ('N', msgBuf.mboname);
  645.       if (msgBuf.mborig[0])
  646.         AddVirtualField ('O', msgBuf.mborig);
  647.       if (msgBuf.mbroom[0])
  648.         AddVirtualField ('R', msgBuf.mbroom);
  649.       if (msgBuf.mbsrcId[0])
  650.         AddVirtualField ('S', msgBuf.mbsrcId);
  651.       if (msgBuf.mbto[0])
  652.         AddVirtualField ('T', msgBuf.mbto);
  653.       if (msgBuf.mbOther[0])
  654.         AddVirtualField ('P', msgBuf.mbOther);
  655.       if (msgBuf.mbdomain[0])
  656.         AddVirtualField ('X', msgBuf.mbdomain);
  657.       if (msgBuf.mbtext[0])
  658.         AddVirtualField ('M', msgBuf.mbtext);
  659.       fclose (upfd);
  660.     }
  661.   else
  662.     printf ("Unable to open %s!\n", fn);
  663.  
  664.   VirtSummary ();
  665.   return 0;
  666. }
  667.  
  668. /*
  669.  * AddVirtualField()
  670.  *
  671.  * This function adds a field to a virtual room message.
  672.  */
  673. void
  674. AddVirtualField (char field, char *contents)
  675. {
  676.   fprintf (upfd, "%c%s", field, contents);
  677.   fputc (0, upfd);
  678. }
  679.  
  680. /*
  681.  * VirtualExists()
  682.  *
  683.  * This function returns an index to given room, if exists.
  684.  */
  685. int
  686. VirtualExists (label name)
  687. {
  688.   int       rover;
  689.  
  690.   for (rover = 0; rover < VirtSize; rover++)
  691.     if (strCmpU (VRoomTab[rover].vrName, name) == SAMESTRING)
  692.       return rover;
  693.  
  694.   return ERROR;
  695. }
  696.  
  697. /*
  698.  * VirtualShared()
  699.  *
  700.  * This function returns an index into current net's virtual index.
  701.  */
  702. int
  703. VirtualShared (int NetNo, label name)
  704. {
  705.   int       rover,
  706.             VirtNo;
  707.  
  708.   if ((VirtNo = VirtualExists (name)) == ERROR)
  709.     return ERROR;
  710.  
  711.   for (rover = 0; rover < VIRT_LIMIT; rover++)
  712.     if (VirtNetList[NetNo].VirtList[rover].WhichVirt == VirtNo)
  713.       return rover;
  714.   return ERROR;
  715. }
  716.  
  717. /*********** These functions stolen & modified from MSG.C ***************/
  718.  
  719. /*
  720.  * doActualWrite()
  721.  *
  722.  * This should allow automatic bkp of msg file from RAM.
  723.  */
  724. char
  725. doActualWrite (whichmsg, mFile, c)
  726.   FILE     *whichmsg;
  727.   struct mBuf *mFile;
  728.   char      c;
  729. {
  730.   MSG_NUMBER temp;
  731.   int       toReturn = 0;
  732.  
  733.   if (mFile->sectBuf[mFile->thisChar] == 0xFF)
  734.     {
  735.  /* obliterating a msg   */
  736.       toReturn = 1;
  737.     }
  738.  
  739.   mFile->sectBuf[mFile->thisChar] = c;
  740.  
  741.   mFile->thisChar = ++mFile->thisChar % MSG_SECT_SIZE;
  742.  
  743.   if (mFile->thisChar == 0)
  744.     {   /* time to write sector out and get next: */
  745.       temp = mFile->thisSector;
  746.       temp *= MSG_SECT_SIZE;
  747.       fseek (whichmsg, temp, 0);
  748.       crypte (mFile->sectBuf, MSG_SECT_SIZE, 0);
  749.       if (fwrite (mFile->sectBuf, MSG_SECT_SIZE, 1, whichmsg) != 1)
  750.         {
  751.           crashout ("?putMsgChar-write fail");
  752.         }
  753.  
  754.       mFile->thisSector = ++mFile->thisSector % cfg.maxMSector;
  755.       temp = mFile->thisSector;
  756.       temp *= MSG_SECT_SIZE;
  757.       fseek (whichmsg, temp, 0);
  758.       if (fread (mFile->sectBuf, MSG_SECT_SIZE, 1, whichmsg) != 1)
  759.         {
  760.           crashout ("?putMsgChar-read fail");
  761.         }
  762.       crypte (mFile->sectBuf, MSG_SECT_SIZE, 0);
  763.     }
  764.   return (char) toReturn;
  765. }
  766.  
  767. /*
  768.  * doFlush()
  769.  *
  770.  * This will do actual writeup for specified msg file.
  771.  */
  772. void
  773. doFlush (whichmsg, mFile)
  774.   FILE     *whichmsg;
  775.   struct mBuf *mFile;
  776. {
  777.   long int  s;
  778.  
  779.   s = mFile->thisSector;
  780.   s *= MSG_SECT_SIZE;
  781.   fseek (whichmsg, s, 0);
  782.   crypte (mFile->sectBuf, MSG_SECT_SIZE, 0);
  783.   if (fwrite (mFile->sectBuf, MSG_SECT_SIZE, 1, whichmsg) != 1)
  784.     {
  785.       crashout ("?ctdlmsg.sys write fail");
  786.     }
  787.   crypte (mFile->sectBuf, MSG_SECT_SIZE, 0);
  788.   fflush (whichmsg);
  789. }
  790.  
  791. /*
  792.  * flushMsgBuf()
  793.  *
  794.  * This wraps up writing a message to disk, takes into account 2nd msg file if
  795.  * necessary.
  796.  */
  797. void
  798. flushMsgBuf ()
  799. {
  800.   doFlush (msgfl, &mFile1);
  801.   if (cfg.BoolFlags.mirror)
  802.     doFlush (msgfl2, &mFile2);
  803. }
  804.  
  805. /*
  806.  * putMessage()
  807.  *
  808.  * This function stores a message to disk.
  809.  * Always called before noteMessage() -- newest not ++ed yet.
  810.  * Returns: TRUE on successful save, else FALSE
  811.  */
  812. void
  813. PutMessage ()
  814. {
  815.   char     temp[40];
  816.   extern char *ALL_LOCALS,
  817.            *WRITE_LOCALS;
  818.   extern char *R_SH_MARK,
  819.            *LOC_NET,
  820.            *NON_LOC_NET;
  821.   char     *s;
  822.  
  823.   startAt (msgfl, &mFile1, cfg.catSector, cfg.catChar);
  824. /* tell putMsgChar where to write   */
  825.   if (cfg.BoolFlags.mirror)
  826.     startAt (msgfl2, &mFile2, cfg.catSector, cfg.catChar);
  827.  
  828.   putMsgChar (0xFF);    /* start-of-message     */
  829.  
  830. /* write message ID */
  831.   sPrintf (temp, "%lu", cfg.newest + 1);
  832.   AddField (0, temp);
  833.  
  834. /* write date:      */
  835.   if (msgBuf.mbdate[0])
  836.     {
  837.       AddField ('D', msgBuf.mbdate);
  838.     }
  839.   else
  840.     {
  841.       AddField ('D', "????");
  842.     }
  843.  
  844. /* write time:      */
  845.   if (msgBuf.mbtime[0])
  846.     {
  847.       AddField ('C', msgBuf.mbtime);
  848.     }
  849.   else
  850.     {
  851.       AddField ('C', "!!!!");
  852.     }
  853.  
  854. /* write author's name out: */
  855.   if (msgBuf.mbauth[0])
  856.     {
  857.       AddField ('A', msgBuf.mbauth);
  858.     }
  859.  
  860. /* write room name out:     */
  861.   AddField ('R', msgBuf.mbroom);
  862.  
  863.   if (msgBuf.mbto[0])
  864.     {   /* private message -- write addressee   */
  865.       AddField ('T', msgBuf.mbto);
  866.     }
  867.  
  868.   if (msgBuf.mbaddr[0])
  869.     {   /* net message routing  */
  870.       if (strCmpU (msgBuf.mbaddr, R_SH_MARK) == SAMESTRING ||
  871.           strCmpU (msgBuf.mbaddr, NON_LOC_NET) == SAMESTRING)
  872.         {
  873.           AddField ('N', msgBuf.mboname);
  874.           if (msgBuf.mborig[0])
  875.             {
  876.               AddField ('O', msgBuf.mborig);
  877.             }
  878.           roomTab[thisRoom].rtlastNet = cfg.newest + 1;
  879.         }
  880.       else if (strCmpU (msgBuf.mbaddr, LOC_NET) == SAMESTRING)
  881.         {
  882.           AddField ('N', msgBuf.mboname);
  883.           if (msgBuf.mborig[0])
  884.             {
  885.               AddField ('O', msgBuf.mborig);
  886.             }
  887.         }
  888.  
  889.       sPrintf (temp, "%s%d", msgBuf.mbaddr, thisNet);
  890.       AddField ('Q', temp);
  891.     }
  892.   else
  893.     {
  894.       if (msgBuf.mboname[0])
  895.         {
  896.           AddField ('N', msgBuf.mboname);
  897.         }
  898.       if (msgBuf.mborig[0])
  899.         {
  900.           AddField ('O', msgBuf.mborig);
  901.         }
  902.     }
  903.  
  904.   if (msgBuf.mbdomain[0])
  905.     {
  906.       AddField ('X', msgBuf.mbdomain);
  907.     }
  908.  
  909.   if (msgBuf.mbsrcId[0])
  910.     {
  911.       AddField ('S', msgBuf.mbsrcId);
  912.     }
  913.  
  914.   if (msgBuf.mbOther[0])
  915.     {
  916.       AddField ('P', msgBuf.mbOther);
  917.     }
  918.  
  919. /* write message text by hand because it would overrun AddField buffer: */
  920.   putMsgChar ('M');     /* M-for-message.       */
  921.   for (s = msgBuf.mbtext; *s; s++)
  922.     putMsgChar (*s);
  923.  
  924.   putMsgChar (0);       /* null to end text     */
  925.   flushMsgBuf ();
  926.  
  927. }
  928.  
  929. /*
  930.  * AddField()
  931.  *
  932.  * This adds a field to the message base.
  933.  */
  934. void
  935. AddField (field, fValue)
  936.   int       field;
  937.   char     *fValue;
  938. {
  939.   int i=0;
  940.   if( debug_flag )
  941.     {
  942.     if( field)
  943.       printf("   %c:%s(",field, fValue);
  944.     else
  945.       printf("NULL:%s(",fValue);
  946.     };
  947.   if (field)
  948.     putMsgChar (field);
  949.   while (*fValue)
  950.     {
  951.     putMsgChar (*fValue++);
  952.     i++;
  953.     };
  954.   putMsgChar (0);       /* End field. */
  955.   if( debug_flag)printf("%d characters)\n", i);
  956. }
  957.  
  958. /*
  959.  * putMsgChar()
  960.  *
  961.  * This function writes successive message chars to disk.
  962.  * Globals:     thisChar=       thisSector=
  963.  * Returns:     ERROR if problems else TRUE.
  964.  */
  965. int
  966. putMsgChar (c)
  967.   int       c;
  968. {
  969.   int       toReturn;
  970.   int       count1,
  971.             count2;
  972.  
  973.   toReturn = TRUE;
  974.   count1 = doActualWrite (msgfl, &mFile1, c);
  975.   if (cfg.BoolFlags.mirror)
  976.     {
  977.       count2 = doActualWrite (msgfl2, &mFile2, c);
  978.       if (count1 != count2)
  979.         printf ("Mirror msg count discrepancy!");
  980.     }
  981.   if (count1)
  982.     ++cfg.oldest;
  983.   return toReturn;
  984. }
  985.  
  986. static label SearchResult;
  987. static char *SearchTarget,
  988.           GetAlias;
  989.  
  990. /*
  991.  * UseNetAlias()
  992.  *
  993.  * This function will find a usenet alias or the converse.
  994.  */
  995. char     *
  996. UseNetAlias (char *Name, char FindAlias)
  997. {
  998.   void     *EatTrans ();
  999.   SListBase Dummy =
  1000.   {NULL, NULL, NULL, NULL, EatTrans};
  1001.   SYS_FILE  fn;
  1002.   char     *c;
  1003.  
  1004.   SearchResult[0] = 0;
  1005.   SearchTarget = Name;
  1006.   if (!FindAlias)
  1007.     while ((c = strchr (Name, ' ')) != NULL)
  1008.       *c = '_';
  1009.   makeSysName (fn, "st-alias.sys", &cfg.roomArea);
  1010.   GetAlias = FindAlias;
  1011.   MakeList (&Dummy, fn, NULL);  /* CHEAT!  WHEEEEEE! */
  1012.   if (strLen (SearchResult) == 0)
  1013.     return NULL;
  1014.   return SearchResult;
  1015. }
  1016.  
  1017. /*
  1018.  * EatTrans()
  1019.  *
  1020.  * This function will eat a line of for the alias mapping.
  1021.  */
  1022. void     *
  1023. EatTrans (char *line)
  1024. {
  1025.   char     *c;
  1026.  
  1027.   if ((c = strchr (line, ' ')) != NULL)
  1028.     {
  1029.       *c = 0;
  1030.       if (GetAlias)
  1031.         {       /* check second field */
  1032.           if (strCmpU (c + 1, SearchTarget) == SAMESTRING)
  1033.             {
  1034.               strCpy (SearchResult, line);
  1035.             }
  1036.         }
  1037.       else
  1038.         {       /* check first field */
  1039.           if (strCmpU (line, SearchTarget) == SAMESTRING)
  1040.             {
  1041.               strCpy (SearchResult, c + 1);
  1042.             }
  1043.         }
  1044.     }
  1045.   return NULL;
  1046. }
  1047.  
  1048. /*
  1049.  * FindRouteSlot()
  1050.  *
  1051.  * This function will find the slot of routing node.  If found, netTemp will
  1052.  * contain the new slot, as will RouteSlot.
  1053.  */
  1054. int
  1055. FindRouteSlot ()
  1056. {
  1057. /*
  1058.  * first check to see if we're the direct (final) link, either
  1059.  * expressly or because the route is outdated.
  1060.  */
  1061.   if (!DirectRoute (&netTemp))  /* expressly?   */
  1062.     getNet ((RouteSlot = netTemp.nbRoute), &netTemp);
  1063.  
  1064.   return RouteSlot;
  1065. }
  1066.  
  1067. /*
  1068.  * DirectRoute()
  1069.  *
  1070.  * This will discover if we directly or indirectly talk to this node.
  1071.  */
  1072. char
  1073. DirectRoute (NetBuffer * n)
  1074. {
  1075.   return (char) (n->nbRoute == -1 ||    /* expressly?   */
  1076.                  !netTab[n->nbRoute].ntflags.in_use ||  /* outdated?    */
  1077.                  netTab[n->nbRoute].ntGen != n->nbRouteGen);    /* outdated? */
  1078. }
  1079.  
  1080. /*
  1081.  * getNetChar()
  1082.  *
  1083.  * This gets a character from a network temporary file.
  1084.  */
  1085. int
  1086. getNetChar ()
  1087. {
  1088.   return -1;    /* actually, this should never be called.       */
  1089. }
  1090.  
  1091. /*
  1092.  * SepNameSystem()
  1093.  *
  1094.  * This will parse an Other Recipient spec.
  1095.  */
  1096. char
  1097. SepNameSystem (char *string, char *person, char *system, NetBuffer * buf)
  1098. {
  1099.   char     *c;
  1100.   int       n;
  1101.   char      work[NAMESIZE * 3];   /* should be sufficient */
  1102.  
  1103.   strCpy (work, string);
  1104.   if ((c = strchr (work, '@')) == NULL)
  1105.     return NOT_SYSTEM;
  1106.  
  1107. /* find leading spaces of "name @ system" format */
  1108.   for (n = 1; c[n] == ' ' && c[n]; n++)
  1109.     ;
  1110.  
  1111.   if (strLen (c + n) >= NAMESIZE)
  1112.     return BAD_FORMAT;
  1113.  
  1114.   strCpy (system, c + n);
  1115.   if (searchNameNet (c + n, buf) == ERROR)      /* bad - set signal of it */
  1116.     return NO_SYSTEM;
  1117.  
  1118.   *c = 0;
  1119.   CleanEnd (work);      /* kill trailing spaces */
  1120.   if (strLen (work) >= NAMESIZE)
  1121.     return BAD_FORMAT;
  1122.  
  1123.   strCpy (person, work);
  1124.  
  1125.   return IS_SYSTEM;
  1126. }
  1127.  
  1128. #define WeServe(x)      SearchList(&Serves, x)
  1129. extern SListBase Serves;
  1130.  
  1131. /*
  1132.  * LocalName()
  1133.  *
  1134.  * This takes a string of form <system> _ <domain> and attempts to discover if
  1135.  * this domain mapped system is actually a local.  This is used when we're
  1136.  * sending mail and are trying to find out if a Who Else override needs to be
  1137.  * generated.  Ugly kludge, but, hey, that's what programming's all about, eh?
  1138.  */
  1139. char     *
  1140. LocalName (char *system)
  1141. {
  1142.   char     *domain,
  1143.            *System;
  1144.  
  1145.   if ((domain = strchr (system, '_')) == NULL)
  1146.     return system;
  1147.   domain += 2;  /* always preceded by a space -- or so we assume */
  1148.  
  1149.   if (strCmpU (domain, cfg.codeBuf + cfg.nodeDomain) == SAMESTRING ||
  1150.       WeServe (domain) != NULL)
  1151.     {
  1152.       System = strdup (system);
  1153.       if ((domain = strchr (System, ' ')) == NULL)
  1154.         return system;  /* should never happen, though */
  1155.       *domain = NULL;
  1156.       if (searchNameNet (System, &netTemp) != ERROR)
  1157.         {
  1158.           free (System);
  1159.           return netTemp.netName;
  1160.         }
  1161.       free (System);
  1162.     }
  1163.   return system;
  1164. }
  1165.  
  1166. /*
  1167.  * mFormat()
  1168.  *
  1169.  * This function formats a string to modem and console.
  1170.  */
  1171. void
  1172. mFormat (char *string)
  1173. {
  1174.   char      wordBuf[MAXWORD];
  1175.   int       i;
  1176.  
  1177.   for (i = 0; string[i];)
  1178.     {
  1179.       i = getWord (wordBuf, string, i, MAXWORD);
  1180.       putWord (wordBuf);
  1181.     }
  1182. }
  1183.  
  1184. /*
  1185.  * getWord()
  1186.  *
  1187.  * This function fetches one word from current message.
  1188.  */
  1189. int
  1190. getWord (char *dest, char *source, int offset, int lim)
  1191. {
  1192.   int       i,
  1193.             j;
  1194.  
  1195. /* skip leading blanks if any */
  1196.   for (i = 0; source[offset + i] == ' ' && i < lim - 1; i++) ;
  1197.  
  1198. /* step over word */
  1199.   for (;
  1200.  
  1201.        source[offset + i] != ' ' &&
  1202.        i < lim - 1 &&
  1203.        source[offset + i] != 0;
  1204.  
  1205.        i++
  1206.     ) ;
  1207.  
  1208.   if (source[offset + i - 1] != '\n')
  1209.  
  1210. /* pick up any trailing blanks */
  1211.     for (; source[offset + i] == ' ' && i < lim - 1; i++) ;
  1212.  
  1213. /* copy word over */
  1214.   for (j = 0; j < i; j++)
  1215.     dest[j] = source[offset + j];
  1216.   dest[j] = 0;  /* null to tie off string */
  1217.  
  1218.   return (offset + i);
  1219. }
  1220.  
  1221. /*
  1222.  * putWord()
  1223.  *
  1224.  * This function writes one word to modem & console.
  1225.  */
  1226. void
  1227. putWord (char *st)
  1228. {
  1229.   char     *s;
  1230.   int       newColumn;
  1231.   static char prevChar = 0;
  1232.  
  1233.   for (newColumn = crtColumn, s = st; *s; s++)
  1234.     {
  1235.       if (*s != TAB)
  1236.         {
  1237.           if (*s == '\b')
  1238.             newColumn--;
  1239.           else
  1240.             ++newColumn;
  1241.         }
  1242.       else
  1243.         while (++newColumn % 8) ;
  1244.     }
  1245.   if (newColumn > termWidth)
  1246.     {
  1247.       fprintf (upfd, "\n");
  1248.       crtColumn = 1;
  1249.     }
  1250.  
  1251.   for (; *st; st++)
  1252.     {
  1253.  
  1254.       if (*st != TAB)
  1255.         {
  1256.           if (*st == '\b')
  1257.             crtColumn--;
  1258.           else
  1259.             ++crtColumn;
  1260.         }
  1261.       else
  1262.         while (++crtColumn % 8) ;
  1263.  
  1264.  /* worry about words longer than a line:        */
  1265.       if (crtColumn > termWidth)
  1266.         {
  1267.           fprintf (upfd, "\n");
  1268.           crtColumn = 1;
  1269.         }
  1270.  
  1271.       if (*st == '\n' && EOP)
  1272.         {
  1273.           fprintf (upfd, "\n");
  1274.           crtColumn = 1;
  1275.         }
  1276.       else if (prevChar != NEWLINE || (*st > ' '))
  1277.         {
  1278.           putc (*st, upfd);
  1279.           prevChar = *st;
  1280.           if (*st > ' ')
  1281.             EOP = FALSE;
  1282.         }
  1283.       else
  1284.         {
  1285.           fprintf (upfd, "\n");
  1286.           crtColumn = 1;
  1287.           if (*st == '\n' && !EOP)
  1288.             {
  1289.               fprintf (upfd, "\n");
  1290.               crtColumn = 1;
  1291.             }
  1292.           else
  1293.             putc (*st, upfd), prevChar = *st;
  1294.           EOP = TRUE;
  1295.         }
  1296.     }
  1297. }
  1298.  
  1299. /*
  1300.    * TranslateFilename()
  1301.    *
  1302.    * This does translations on a filename.  This is used for embedding dates
  1303.    * or numbers into a filename.
  1304.  */
  1305. void
  1306. TranslateFilename (char *realfn, char *fn)
  1307. {
  1308.   int       year,
  1309.             day,
  1310.             hours,
  1311.             minutes;
  1312.   char     *month;
  1313.  
  1314.   getCdate (&year, &month, &day, &hours, &minutes);
  1315.   *realfn = '\0';
  1316.   while (*fn)
  1317.     {
  1318.       if (*fn == '%')
  1319.         {
  1320.           fn++;
  1321.           switch (*fn)
  1322.             {
  1323.               case 'm':
  1324.               case 'M':
  1325.                 sPrintf (realfn, "%s", month);
  1326.                 realfn += 3;
  1327.                 break;
  1328.               case 'y':
  1329.               case 'Y':
  1330.                 sPrintf (realfn, "%d", year);
  1331.                 realfn += 2;
  1332.                 break;
  1333.             };
  1334.           fn++;
  1335.         }
  1336.       else
  1337.         {
  1338.           *realfn++ = *fn++;
  1339.         };
  1340.       *realfn = '\0';
  1341.     }
  1342. }
  1343.  
  1344. void
  1345. netResult (char *msg)
  1346. {
  1347.   printf ("%s\n", msg);
  1348. }
  1349.  
  1350. char     *MonthTab[] =
  1351. {
  1352.   "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE",
  1353.   "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER"
  1354.  
  1355. };
  1356.  
  1357. char     *KeyWords[] =
  1358. {
  1359.   "TODAY", "YESTERDAY"
  1360.  
  1361. };
  1362.  
  1363. char      DayPMonth[] =
  1364. {
  1365.   31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  1366.  
  1367. };
  1368.  
  1369. /*
  1370.  * getCdate()
  1371.  *
  1372.  * This retrieves system date and returns in the parameters.
  1373.  */
  1374. void
  1375. getCdate (int *year, char **month, int *day, int *hours, int *minutes)
  1376. {
  1377.   int       mon,
  1378.             seconds,
  1379.             milli;
  1380.  
  1381.   getRawDate (year, &mon, day, hours, minutes, &seconds, &milli);
  1382.   *year -= 1900;
  1383.   *month = MonthTab[mon];
  1384.  
  1385. }
  1386.  
  1387. void      Do_Stack_Check (void);
  1388.  
  1389. #define LeapYear(x)     ((x % 4) ? FALSE : ((year % 100) ? TRUE : FALSE))
  1390. /************************************************************************/
  1391. /*      ReadDate() interprets the string and returns it in seconds      */
  1392. /************************************************************************/
  1393. int
  1394. ReadDate (char *date, long *RetTime)
  1395. {
  1396.   int       rover,
  1397.             found,
  1398.             keyword = -1;
  1399.   int       year,
  1400.             month,
  1401.             day,
  1402.             hours,
  1403.             minutes,
  1404.             seconds,
  1405.             milli;
  1406.   label     mon;
  1407.   char     *d = date;
  1408.   char      darray[6];            /* see format for utpack() */
  1409.  
  1410.   Do_Stack_Check ();
  1411.   if (strLen (date) == 0)
  1412.     return FALSE;
  1413.   if (isdigit (date[0]))
  1414.     {
  1415.       darray[0] = (char) (atoi (date) + 1900 - 1970);
  1416.       while (isdigit (*date))
  1417.         date++;
  1418.  
  1419.     }
  1420.   else
  1421.     {
  1422.       getRawDate (&year, &month, &day, &hours, &minutes,
  1423.                   &seconds, &milli);
  1424.       year -= 1970;
  1425.       darray[0] = (char) year;
  1426.       darray[1] = (char) month;
  1427.       darray[2] = (char) day;
  1428.  
  1429.     }
  1430.   for (rover = 0; isalpha (*date); date++, rover++)
  1431.     mon[rover] = toUpper (*date);
  1432.   mon[rover] = 0;
  1433.   if (rover == 0)
  1434.     {
  1435.       if (isdigit (d[0]))
  1436.         {
  1437.           *RetTime = CurAbsolute () - (atol (d) * 86400l);
  1438.           return TRUE;
  1439.         }
  1440.       return ERROR;
  1441.     };
  1442.   for (found = rover = 0; rover < NumElems (MonthTab); rover++)
  1443.     if (strncmp (mon, MonthTab[rover], strLen (mon)) == SAMESTRING)
  1444.       {
  1445.         found++;
  1446.         darray[1] = (char) (rover + 1);
  1447.  
  1448.       }
  1449.   if (found != 1)
  1450.     {
  1451.       for (keyword = -1, rover = 0; rover < NumElems (KeyWords); rover++)
  1452.         if (strncmp (mon, KeyWords[rover], strLen (mon)) == SAMESTRING)
  1453.           {
  1454.             keyword = rover;
  1455.  
  1456.           }
  1457.       if (keyword == -1)
  1458.         return ERROR;
  1459.       else
  1460.         {
  1461.           switch (keyword)
  1462.             {
  1463.               case 0:   /* TODAY */
  1464.                 break;
  1465.               case 1:   /* YESTERDAY */
  1466.                 --darray[2];
  1467.                 if (!darray[2])
  1468.                   {
  1469.                     --darray[1];
  1470.                     if (!darray[1])
  1471.                       {
  1472.                         darray[1] = 12;
  1473.                         --darray[0];
  1474.  
  1475.                       }
  1476.                     darray[2] = DayPMonth[darray[1] - 1];
  1477.                     if (darray[1] == 2 && LeapYear (darray[0]))
  1478.                       darray[2] = 29;
  1479.  
  1480.                   }
  1481.                 break;
  1482.  
  1483.             }
  1484.  
  1485.         }
  1486.  
  1487.     }
  1488.   if ((keyword == -1) && ((darray[2] = (char) atoi (date)) == 0))
  1489.     return ERROR;
  1490.   darray[3] = 0;
  1491.   darray[4] = 0;
  1492.   darray[5] = 0;
  1493.   *RetTime = utpack (darray);
  1494.   return TRUE;
  1495.  
  1496. }
  1497.  
  1498. /************************************************************************/
  1499. /*      CurAbsolute() current time in absolute terms.                   */
  1500. /************************************************************************/
  1501. long
  1502. CurAbsolute ()
  1503. {
  1504.   Do_Stack_Check ();
  1505.   return time (NULL);
  1506.  
  1507. }
  1508.